package com.gitee.feizns.quickstart.web.spring.boot.autoconfigure.restful;

import com.gitee.feizns.dynamic.Strings;
import com.gitee.feizns.quickstart.domain.vo.Ret;
import com.gitee.feizns.quickstart.spring.AppUtils;
import com.gitee.feizns.quickstart.web.ex.GlobalRestfulExceptionAdvice;
import com.gitee.feizns.quickstart.web.restful.Rests;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.servlet.function.RouterFunctions;
import org.springframework.web.servlet.function.ServerRequest;
import org.springframework.web.servlet.function.ServerResponse;

import java.util.Objects;

/**
 * REST ful Router 函数创建器
 * @author feizns
 * @since 2024/10/30
 */
public interface RestfulRouterFunctionCreator {

    /**
     * 创造路由
     * @param routeClass Route 类
     * @return {@link RouterFunctions.Builder }
     */
    static RouterFunctions.Builder route(Class<?> routeClass) {
        RestApi restApi = routeClass.getAnnotation(RestApi.class);
        RouterFunctions.Builder builder = RouterFunctions.route();
        Class<?> modelClass = Rests.type(routeClass);
        //注册RestfulApi
        restfulApiRoute(builder, restApi, modelClass);
        return builder.onError(Throwable.class, RestfulRouterFunctionCreator::onError);
    }

    /**
     * 创建crud路由器函数
     * @param builder 建筑工人
     * @param api 应用程序接口
     * @param modelClass 模型类
     */
    static <T> void restfulApiRoute(RouterFunctions.Builder builder, RestApi api, Class<T> modelClass) {
        //url前缀
        String apiUrlPrefix = api.prefix() + "/" + Strings.toHyphenNaming(modelClass.getSimpleName()).toLowerCase();
        //需要注册的方法
        for (RestApi.Method method : api.methods()) {
            //基础增删改查路由创建
            if ( method == RestApi.Method.Create )
                builder.POST(apiUrlPrefix, req -> ServerResponse.ok().body(Rests.crud(modelClass)));
            else if ( method == RestApi.Method.Delete )
                builder.DELETE(apiUrlPrefix, req -> ServerResponse.ok().body(Rests.crud(modelClass)));
            else if ( method == RestApi.Method.Put )
                builder.PUT(apiUrlPrefix, req -> ServerResponse.ok().body(Rests.crud(modelClass)));
            else if ( method == RestApi.Method.Patch )
                builder.PATCH(apiUrlPrefix, req -> ServerResponse.ok().body(Rests.crud(modelClass)));
            else if ( method == RestApi.Method.Page )
                builder.GET(apiUrlPrefix, req -> ServerResponse.ok().body(Rests.crud(modelClass)));
            else if ( method == RestApi.Method.PutById )
                builder.PUT(apiUrlPrefix + "/{id}", req -> ServerResponse.ok().body(Rests.crudById(modelClass, req.pathVariable("id"))));
            else if ( method == RestApi.Method.PatchById )
                builder.PATCH(apiUrlPrefix + "/{id}", req -> ServerResponse.ok().body(Rests.crudById(modelClass, req.pathVariable("id"))));
            else if ( method == RestApi.Method.DeleteById )
                builder.DELETE(apiUrlPrefix + "/{id}", req -> ServerResponse.ok().body(Rests.crudById(modelClass, req.pathVariable("id"))));
            else if ( method == RestApi.Method.GetById )
                builder.GET(apiUrlPrefix + "/{id}", req -> ServerResponse.ok().body(Rests.crudById(modelClass, req.pathVariable("id"))));
        }
    }

    /**
     * 处理函数
     * @param request 请求
     * @return {@link ServerResponse}
     */
    static ServerResponse onError(Throwable throwable, ServerRequest request) {
        if ( throwable instanceof Exception ) {
            GlobalRestfulExceptionAdvice bean = AppUtils.getBean(GlobalRestfulExceptionAdvice.class);
            ResponseEntity<?> response = bean.exceptionHandle((Exception) throwable);
            return ServerResponse.status(response.getStatusCodeValue()).body(Objects.requireNonNull(response.getBody()));
        }
        return ServerResponse.status(HttpStatus.INTERNAL_SERVER_ERROR).body(Ret.error(throwable.getMessage()));
    }

}
